package com.desksoft.ecommerce.util.html;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.desksoft.ecommerce.util.html.element.PageElement;
import com.desksoft.ecommerce.util.html.element.PageEventElement;
import com.desksoft.ecommerce.util.html.element.QueryElement;
import com.desksoft.ecommerce.util.html.element.data.PageCheckBoxDataElement;
import com.desksoft.ecommerce.util.html.element.data.PageRadioDataElement;
import com.desksoft.ecommerce.util.html.element.data.PageSelectDataElement;
import com.desksoft.ecommerce.util.html.element.data.PageTextDataElement;
import com.desksoft.ecommerce.util.html.element.data.linkinput.LinkInputElement;
import com.desksoft.ecommerce.util.html.element.data.validata.ValidataElement;
import com.desksoft.ecommerce.util.html.element.format.DisplayFormat;
import com.desksoft.ecommerce.util.html.element.query.PlaceholderParameter;
import com.desksoft.ecommerce.util.html.element.query.PrepareProcedure;
import com.desksoft.ecommerce.util.html.element.query.PrepareSql;
import com.desksoft.ecommerce.util.html.element.query.QueryProcedureElement;
import com.desksoft.ecommerce.util.html.element.query.QuerySqlElement;
import com.desksoft.ecommerce.util.html.element.variable.VariableCollection;
import com.desksoft.ecommerce.util.html.view.print.PrintElement;
import com.desksoft.ecommerce.util.html.view.subtable.RelationKey;
import com.desksoft.ecommerce.util.html.view.subtable.SubTable;
import com.desksoft.ecommerce.util.html.view.table.MainTable;
import com.desksoft.utility.encode.EncodeUtil;
import com.desksoft.utility.query.FieldSymbol;

/***************************************
 * 版权所有：杭州迪科软件 保留所有权利
 * 创建日期: 
 * 创建作者：luoy
 * 文件名称：解析Xml文件(描述查询信息的Xml文件)
 * 版本：
 * 功能：
 * 最后修改时间：
 * 修改记录：
 *****************************************/
public class PageXml implements Serializable {
	
	protected Document rootDocument;
	protected Element rootElement;			//	根节点信息
	
	protected String moduId;				//	从属模块ID
	protected VariableCollection varCollection;		//	系统默认值集合
	
	protected String pagehtml;				//	页面HTML元素
	protected String pagequery;				//	页面查询元素
	protected String viewtype = "table";	//	明细区显示方式
	
	protected SubTable[] subTableA;			//	主从关系表
	protected DisplayFormat[] formatA = new DisplayFormat[0];		//	表格格式化
	
	protected List<PageElement> needsQueryElement = new ArrayList<PageElement>();	//	需要使用查询才能初始化的页面元素
	protected List<ValidataElement> validataL = new ArrayList<ValidataElement>();	//	页面验证元素
	protected List<LinkInputElement> linkInputL = new ArrayList<LinkInputElement>();	//	关联输入元素
	protected PrintElement printElement = new PrintElement();
	protected List<MainTable> mainTableL = new ArrayList<MainTable>();
	protected List<PrepareSql> prepareL = new ArrayList<PrepareSql>();		//	事先准备切换的Sql语句
	protected List<PrepareProcedure> prepareProcedureL = new ArrayList<PrepareProcedure>();	//	事先准备好切换的存储过程
	protected List<PlaceholderParameter> placeholderL;	//事先准备好的参数占位符
	
	/**
	 * 页面事件对象
	 */
	protected List<PageEventElement> eventL = new ArrayList<PageEventElement>();
	
	/**
	 * 生成页面描述
	 * @param inputStream	页面描述文件
	 * @throws DocumentException
	 */
	public PageXml(InputStream inputStream) throws DocumentException{
		SAXReader reader = new SAXReader(); 
		rootDocument = reader.read(inputStream);
		rootElement = rootDocument.getRootElement();
		this.parse();
	}
	
	/**
	 * 生成页面描述
	 * @param 	inputStream	页面描述文件
	 * @param	当前模块ID
	 * @throws DocumentException
	 */
	public PageXml(InputStream inputStream,String moduId , VariableCollection varCollection) throws DocumentException{
		this.moduId = "div#"+moduId+" ";
		this.varCollection = varCollection;
		SAXReader reader = new SAXReader(); 
		rootDocument = reader.read(inputStream);
		rootElement = rootDocument.getRootElement();
		this.parse();
	}
	
	/**
	 * 
	 * @param path	页面描述文件
	 * @throws DocumentException 
	 * @throws FileNotFoundException 
	 */
	public PageXml(String path) throws FileNotFoundException, DocumentException{
		this(new FileInputStream(path));
	}
	
	/**
	 * 
	 * @param file	页面描述文件
	 * @throws DocumentException 
	 * @throws FileNotFoundException 
	 */
	public PageXml(File file) throws FileNotFoundException, DocumentException{
		this(new FileInputStream(file));
	}
	
	public PageXml(InputStream inputStream, String moduleId) throws DocumentException {
		this.moduId = "div#"+moduId+" ";
		SAXReader reader = new SAXReader(); 
		rootDocument = reader.read(inputStream);
		rootElement = rootDocument.getRootElement();
//		this.parse();
	}

	/**
	 * 解析页面Xml文件
	 */
	public void parse(){
		this.html = new PageElement();
		Element htmlElement = this.rootElement.element("htmlElement");
		parsePageElement(htmlElement,this.html);
		
		Element queryElement = this.rootElement.element("queryElement");
		this.query = parseQueryElement(queryElement);
		try {
			Element elmtPrepare = queryElement.element("prepare");
			this.prepareL.addAll(this.parsePrepareSql(elmtPrepare));
			this.prepareProcedureL.addAll(this.parsePrepareProcedure(elmtPrepare));
			this.placeholderL = this.parsePlaceholderParameter(queryElement.element("placeholderparameter"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		Element viewElement = this.rootElement.element("viewElement");
		if (viewElement != null){
			Element view = viewElement.element("view");
			if (view != null && "print".equals(view.attribute("type"))){
				this.setViewtype("print");
			}
			this.setSubTableA(parseSubTable(viewElement));
			this.setFormatA(parseDisplayFormat(viewElement));
			this.setPrintElement(parsePrintElement(viewElement));
			this.setMainTableL(parseMainTable(viewElement));
		}
	}
	
	/**
	 * 解析页面元素
	 * @param	element 	页面元素标签
	 */
	public void parsePageElement(Element element,PageElement parentElement){
		
		String target = element.attributeValue("target");
		PageElement pageElement = null;
		if ("input".equals(target)){
			pageElement = new PageTextDataElement(element,this);
		}else if ("select".equals(target)){
			pageElement = new PageSelectDataElement(element,this);
		}else if ("radio".equals(target)){
			pageElement = new PageRadioDataElement(element,this);
		}else if ("checkbox".equals(target)){
			pageElement = new PageCheckBoxDataElement(element,this);
		}
		else{
			pageElement = new PageElement(element);
		}
		parentElement.getChildren().add(pageElement);
		
		pageElement.setChildren(new ArrayList<PageElement>());
		List<Element> targetElementL = element.elements("targetElement");
		if (targetElementL == null ||targetElementL.size() == 0){
			return;
		}else{
			for (Element e:targetElementL){
				parsePageElement(e,pageElement);
			}
		}
	}
	
	/**
	 * 解析事先准备好的参数占位符
	 */
	public List<PlaceholderParameter> parsePlaceholderParameter(Element placeholdeElement){
		if (placeholdeElement == null){
			return new ArrayList<PlaceholderParameter>(0);
		}
		
		Element mapElmt = placeholdeElement.element("map");
		List<Element> entryElmtL = mapElmt.elements("entry");
		List<PlaceholderParameter> placeholderL = new ArrayList<PlaceholderParameter>(entryElmtL.size());
		
		for (Element entryElmt : entryElmtL){
			placeholderL.add(new PlaceholderParameter(entryElmt));
		}
		
		return placeholderL;
		
	}
	
	/**
	 * 解析事先准备好的存储过程
	 */
	public List<PrepareProcedure> parsePrepareProcedure(Element elmtPrepare){
		
		if (elmtPrepare == null){
			return new ArrayList<PrepareProcedure>();
		}
		Element elmtProcedure = elmtPrepare.element("procedure");
		if (elmtProcedure == null){
			return new ArrayList<PrepareProcedure>();
		}
		
		List<Element> elmtL = elmtProcedure.elements("procedure");
		List<PrepareProcedure> ppL = new ArrayList<PrepareProcedure>();
		for (Element elmt : elmtL){
			String id = elmt.attributeValue("id");
			QueryProcedureElement procedure = new QueryProcedureElement(elmt, this);
			ppL.add(new PrepareProcedure(id, procedure));
		}
		
		return ppL;
	}
	
	/**
	 * 解析事先准备好的 Sql 语句
	 * @throws Exception 
	 */
	public List<PrepareSql> parsePrepareSql(Element elmtPrepare) throws Exception{
		if (elmtPrepare == null){
			return new ArrayList<PrepareSql>();
		}
		List<Element> elmtL = elmtPrepare.elements("sql");
		List<PrepareSql> prepareL = new ArrayList<PrepareSql>();
		for (Element elmt : elmtL){
			String id = elmt.attributeValue("id"),
					sql = this.getVarCollection().replaceSql(elmt.getText().replaceAll("\n", "").replaceAll("\t", " "));
			prepareL.add(new PrepareSql(id, EncodeUtil.encipherment(sql, "sql")));
		}
		return prepareL;
	}
	
	/**
	 * 解析查询元素
	 * ----	优先使用Sql语句查询
	 */
	public QueryElement parseQueryElement(Element element){
		Element sqlElement = element.element("sqlElement");
		QueryElement query;
		if (sqlElement != null){
			QuerySqlElement querySqlElement = new QuerySqlElement(sqlElement, this);
			query = querySqlElement;
			return query;
		}
		sqlElement = element.element("procedureElement");
		if (sqlElement != null){
			QueryProcedureElement procedureElement = new QueryProcedureElement(sqlElement, this);
			query = procedureElement;
			return query;
		}
		return null;
	}
	
	/**
	 * 解析主表元素
	 */
	public List<MainTable> parseMainTable(Element element){
		
		Element elmtView = element.element("view");
		if (elmtView == null){
			return new ArrayList<MainTable>(0);
		}
		
		List<Element> elmtTables = elmtView.elements("table");
		List<MainTable> mainTableL = new ArrayList<MainTable>();
		
		for (Element elmt : elmtTables){
			mainTableL.add(new MainTable(elmt, this));
		}
		
		return mainTableL;
	}
	
	/**
	 * 解析打印参数
	 */
	public PrintElement parsePrintElement(Element element){
		
		Element elmtPrint = element.element("print");
		if (elmtPrint != null){
			return new PrintElement(elmtPrint);
		}else{
			return new PrintElement();
		}
	}
	
	/**
	 * 解析表格格式化
	 */
	public DisplayFormat[] parseDisplayFormat(Element element){
		Element formatterElmt = element.element("formatter");
		if (formatterElmt == null){
			return new DisplayFormat[0];
		}
		List<Element> formatElementL = formatterElmt.elements("display-format");
		DisplayFormat[] formatA = new DisplayFormat[formatElementL.size()];
		for (int i = 0 ; i < formatA.length ; i++){
			formatA[i] = new DisplayFormat(formatElementL.get(i), this);
		}
		return formatA;
	}
	
	/**
	 * 解析主从关系表
	 */
	public SubTable[] parseSubTable(Element element){
		List<Element> subtableElementL = element.elements("subtable");
		SubTable[] subTableA = new SubTable[subtableElementL.size()];
		
		Element subtableElement,manyToOneElement;
		SubTable subtable;
		String id;
		for (int i=0;i<subtableElementL.size();i++){
			subtable = new SubTable();
			subtableElement = subtableElementL.get(i);
			subtable.setId(subtableElement.attributeValue("id"));
			subtable.setContainer(subtableElement.attributeValue("container"));
			manyToOneElement = subtableElement.element("many-to-one");
			parseRelationKey(manyToOneElement,subtable);
			subtable.setQuery(parseQueryElement(subtableElement.element("queryElement")));
			if (subtable.getQuery() instanceof QuerySqlElement){
				subtable.setQueryType("sql");
			}else{
				subtable.setQueryType("procedure");
			}
			subTableA[i] = subtable;
		}
		return subTableA;
	}
	
	/**
	 * 解析主从关系表依赖关系
	 */
	public void parseRelationKey(Element element,SubTable subtable){
		subtable.setMainTableId(element.attributeValue("table"));
		List<Element> keyElementL = element.elements("key");
		Element keyElement;
		RelationKey[] relationKeyA = new RelationKey[keyElementL.size()];
		RelationKey rk;
		for (int i=0;i<keyElementL.size();i++){
			keyElement = keyElementL.get(i);
			rk = new RelationKey();
			rk.setMainKey(keyElement.attributeValue("point"));
			rk.setSubKey(keyElement.attributeValue("column"));
			String symbol = keyElement.attributeValue("symbol");
			String dataType = keyElement.attributeValue("dataType");
			if (dataType == null){
				dataType = "java.lang.String";
			}
			if (symbol == null){symbol = "eq";}
			rk.setSymbol(FieldSymbol.valueOf(symbol));
			rk.setDataType(dataType);
			relationKeyA[i]=rk;
		}
		subtable.setRelationKeyA(relationKeyA);
	}
	
	protected PageElement html;
	protected QueryElement query;

	public String getPagehtml() {
		if (pagehtml == null){
			pagehtml = this.html.toHtml();
		}
		return pagehtml;
	}

	public void setPagehtml(String pagehtml) {
		this.pagehtml = pagehtml;
	}

	public PageElement getHtml() {
		return html;
	}
	public void setHtml(PageElement html) {
		this.html = html;
	}
	public QueryElement getQuery() {
		return query;
	}
	public void setQuery(QueryElement query) {
		this.query = query;
	}

	public String getViewtype() {
		return viewtype;
	}

	public void setViewtype(String viewtype) {
		this.viewtype = viewtype;
	}

	public SubTable[] getSubTableA() {
		return subTableA;
	}

	public void setSubTableA(SubTable[] subTableA) {
		this.subTableA = subTableA;
	}

	public List<PageElement> getNeedsQueryElement() {
		return needsQueryElement;
	}

	public void setNeedsQueryElement(List<PageElement> needsQueryElement) {
		this.needsQueryElement = needsQueryElement;
	}

	public List<ValidataElement> getValidataL() {
		return validataL;
	}

	public void setValidataL(List<ValidataElement> validataL) {
		this.validataL = validataL;
	}

	public List<LinkInputElement> getLinkInputL() {
		return linkInputL;
	}

	public void setLinkInputL(List<LinkInputElement> linkInputL) {
		this.linkInputL = linkInputL;
	}

	public String getModuId() {
		return moduId;
	}

	public void setModuId(String moduId) {
		this.moduId = moduId;
	}

	public DisplayFormat[] getFormatA() {
		return formatA;
	}

	public void setFormatA(DisplayFormat[] formatA) {
		this.formatA = formatA;
	}

	public VariableCollection getVarCollection() {
		return varCollection;
	}

	public void setVarCollection(VariableCollection varCollection) {
		this.varCollection = varCollection;
	}

	public PrintElement getPrintElement() {
		return printElement;
	}

	public void setPrintElement(PrintElement printElement) {
		this.printElement = printElement;
	}

	public List<MainTable> getMainTableL() {
		return mainTableL;
	}

	public void setMainTableL(List<MainTable> mainTableL) {
		this.mainTableL = mainTableL;
	}

	public List<PageEventElement> getEventL() {
		return eventL;
	}

	public void setEventL(List<PageEventElement> eventL) {
		this.eventL = eventL;
	}

	public List<PrepareSql> getPrepareL() {
		return prepareL;
	}

	public void setPrepareL(List<PrepareSql> prepareL) {
		this.prepareL = prepareL;
	}

	public List<PrepareProcedure> getPrepareProcedureL() {
		return prepareProcedureL;
	}

	public void setPrepareProcedureL(List<PrepareProcedure> prepareProcedureL) {
		this.prepareProcedureL = prepareProcedureL;
	}

	public List<PlaceholderParameter> getPlaceholderL() {
		return placeholderL;
	}

	public void setPlaceholderL(List<PlaceholderParameter> placeholderL) {
		this.placeholderL = placeholderL;
	}

}
